package edu.ynu.se.xiecheng.achitectureclass.service;

import edu.ynu.se.xiecheng.achitectureclass.common.service.LogicService;
import edu.ynu.se.xiecheng.achitectureclass.dao.DeviceDao;
import edu.ynu.se.xiecheng.achitectureclass.dto.DeviceDataDTO;
import edu.ynu.se.xiecheng.achitectureclass.entity.Device;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.util.*;

@Service
@PropertySource("classpath:application.properties")
public class DeviceService extends LogicService<DeviceDao, Device, Long> {

    private final GreenhouseService greenhouseService;
    private final CameraService cameraService;
    private final List<Object> services;
    public DeviceService(@Autowired DeviceDao dao, GreenhouseService greenhouseService
            , AirTemperatureService airTemperatureService, CarbonDioxideService carbonDioxideService
            , SoilMoistureContentService soilMoistureContentService, SoilPHService soilPHService
            , SoilTemperatureService soilTemperatureService, CameraService cameraService) {
        super(dao);
        this.greenhouseService = greenhouseService;
        this.cameraService = cameraService;
        this.services = Arrays.asList(airTemperatureService, carbonDioxideService, soilMoistureContentService, soilPHService, soilTemperatureService);
    }

    //添加默认设备
    @Transactional
    public void addDefaultDevice() {
        if (dao.count() > 0) return;

        List<Device> devices = new ArrayList<>(Arrays.asList(
                createDevice("空气温度检测器", "空气温度", "327061330933584659", "℃"),
                createDevice("二氧化碳检测器", "二氧化碳", "327061330932536081", "ppm"),
                createDevice("土壤含水率检测器", "土壤含水率", "327061330933584660", "%"),
                createDevice("土壤 PH 值检测器", "土壤PH值", "327061330932536076", "pH"),
                createDevice("土壤温度检测器", "土壤温度", "327061330933584661", "℃"),
                createDevice("萤石摄像头", "萤石摄像头", "AB9831218",null)
        ));
        for (Device device : devices) {
            if (Objects.equals(device.getDeviceSerialNumber(), "AB9831218"))
                device.setMonitorAddresses("ezopen://open.ys7.com/AB9831218/1.hd.live");
            device.setGreenhouse(greenhouseService.getAll().get(0));
        }
        dao.saveAll(devices);
    }

    private Device createDevice(String type, String name, String serialNumber, String unit) {
        Device device = new Device();
        device.setType(type);
        device.setName(name);
        device.setDeviceSerialNumber(serialNumber);
        device.setUnit(unit);
        return device;
    }

    //获取摄像机拍摄的相片
    @Value("${camera.capturedImg}")
    private String capturedImg;

    public String getNewCameraPhoto() throws IOException {
        if (dao.findByName("萤石摄像头").isPresent()) {
            Device device = dao.findByName("萤石摄像头").get();
            String cameraSerialNumber = device.getDeviceSerialNumber();
            String url = cameraService.getPictureUrl(cameraSerialNumber, 1);
            String savedPath =  cameraService.downloadImage(url, capturedImg);
            cameraService.saveCameraPhoto(savedPath, device);
            return savedPath;
        }
        return null;
    }

    //获取各个传感器的数据
    @Value("${fbox.dataUrl}")
    private String dataUrl;
    @Value("${fbox.boxNo}")
    private String boxNo;
    @Value("${fbox.access_token}")
    private String accessToken;

    @Transactional
    public List<String> getDevicesIds() {
        List<Device> devices =  dao.findAll(Sort.by(Sort.Direction.ASC, "id"));
        List<String> ids = new ArrayList<>();
        for (Device device : devices) {
            if(!Objects.equals(device.getType(), "摄像头"))
                ids.add(device.getDeviceSerialNumber());
        }
        return ids;
    }
    @Transactional
    public void getNewDeviceData(List<String> ids, String accessToken) {
        List<Map<String, Object>>  Data =  fetchData(ids, accessToken);
        int index = 0;
        for (Map<String, Object> map : Data) {
               String name = map.get("name").toString();
               Double data = Double.parseDouble(map.get("value").toString());
               Device device = null;
               if (dao.findByName(name).isPresent()) {
                    device = dao.findByName(name).get();
               }

               Object service = services.get(index);
                if (service instanceof AirTemperatureService) {
                    ((AirTemperatureService) service).SaveData(name, data,device);
                } else if (service instanceof CarbonDioxideService) {
                    ((CarbonDioxideService) service).SaveData(name, data,device);
                } else if (service instanceof SoilMoistureContentService) {
                    ((SoilMoistureContentService) service).SaveData(name, data,device);
                } else if (service instanceof SoilPHService) {
                    ((SoilPHService) service).SaveData(name, data,device);
                } else if (service instanceof SoilTemperatureService) {
                    ((SoilTemperatureService) service).SaveData(name, data,device);
                }
                index++;
            }
        }

    private List<Map<String, Object>> fetchData(List<String> ids, String accessToken) {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(dataUrl);
        String url = builder.buildAndExpand(boxNo).toUriString(); // 替换 URL 中的 [boxNo] 占位符
        RestTemplate restTemplate = new RestTemplate();

        // 设置请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("ids", ids);

        // 创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + accessToken);

        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

        // 使用 ParameterizedTypeReference 来安全指定返回类型
        ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                entity,
                new ParameterizedTypeReference<>() {
                }
        );

        // 解析响应数据
        if (response.getStatusCode() == HttpStatus.OK) {
            return response.getBody();  // 返回 List<Map<String, Object>> 类型的数据
        } else {
            throw new RuntimeException("Failed to fetch data.");
        }
    }

    @Transactional
    public void getDevicesData() {
        List<String> ids = getDevicesIds();
        getNewDeviceData(ids, accessToken);
    }

    @Transactional
    public List<DeviceDataDTO> getLatestDevicesData() {
        int index = 0;
        List<DeviceDataDTO> deviceDataDTOs = new ArrayList<>();
        List<Device> allDevices = dao.findAll();
        for(Device device : allDevices){
            if(!Objects.equals(device.getType(), "摄像头")){
                String name = device.getName();
                String unit = device.getUnit();
                DeviceDataDTO deviceDataDTO = new DeviceDataDTO();
                Object service = services.get(index);
                if (service instanceof AirTemperatureService) {
                    deviceDataDTO.setName(name);
                    deviceDataDTO.setData(((AirTemperatureService)service).getLatestData()+unit);
                } else if (service instanceof CarbonDioxideService) {
                    deviceDataDTO.setName(name);
                    deviceDataDTO.setData(((CarbonDioxideService)service).getLatestData()+unit);
                } else if (service instanceof SoilMoistureContentService) {
                    deviceDataDTO.setName(name);
                    deviceDataDTO.setData(((SoilMoistureContentService)service).getLatestData()+unit);
                } else if (service instanceof SoilPHService) {
                    deviceDataDTO.setName(name);
                    deviceDataDTO.setData(((SoilPHService)service).getLatestData()+unit);
                } else if (service instanceof SoilTemperatureService) {
                    deviceDataDTO.setName(name);
                    deviceDataDTO.setData(((SoilTemperatureService)service).getLatestData()+unit);
                }
                deviceDataDTOs.add(deviceDataDTO);
                index++;
            }
        }
        return  deviceDataDTOs;
    }
}
